import { Directive } from "vue";
/**
 *
 * @param component 需要注册的组件
 * @param alias 组件别名
 * @returns any
 */
export const withInstall = <T>(component: T, alias?: string) => {
	const comp = component as any;
	comp.install = (app: any) => {
		app.component(comp.name || comp.displayName, component);
		if (alias) {
			app.config.globalProperties[alias] = component;
		}
	};
	return component as T & Plugin;
};

/**
 * @param str 需要转下划线的驼峰字符串
 * @returns 字符串下划线
 */
export const humpToUnderline = (str: string): string => {
	return str.replace(/([A-Z])/g, "-$1").toLowerCase();
};

/**
 * @param str 需要转驼峰的下划线字符串
 * @returns 字符串驼峰
 */
export const underlineToHump = (str: string): string => {
	if (!str) return "";
	return str.replace(/\-(\w)/g, (_, letter: string) => {
		return letter.toUpperCase();
	});
};

export const setCssVar = (prop: string, val: any, dom = document.documentElement) => {
	dom.style.setProperty(prop, val);
};

/**
 * 查找数组对象的某个下标
 * @param {Array} ary 查找的数组
 * @param {Functon} fn 判断的方法
 */
// eslint-disable-next-line
export const findIndex = <T = Recordable>(ary: Array<T>, fn: Fn): number => {
	if (ary.findIndex) {
		return ary.findIndex(fn);
	}
	let index = -1;
	ary.some((item: T, i: number, ary: Array<T>) => {
		const ret: T = fn(item, i, ary);
		if (ret) {
			index = i;
			return ret;
		}
	});
	return index;
};

export const trim = (str: string) => {
	return str.replace(/(^\s*)|(\s*$)/g, "");
};

/**
 * @param {Date | number | string} time 需要转换的时间
 * @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss
 */
export const formatTime = (time: Date | number | string, fmt: string) => {
	if (!time) return "";
	else {
		const date = new Date(time);
		const o = {
			"M+": date.getMonth() + 1,
			"d+": date.getDate(),
			"H+": date.getHours(),
			"m+": date.getMinutes(),
			"s+": date.getSeconds(),
			"q+": Math.floor((date.getMonth() + 3) / 3),
			S: date.getMilliseconds()
		};
		if (/(y+)/.test(fmt)) {
			fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
		}
		for (const k in o) {
			if (new RegExp("(" + k + ")").test(fmt)) {
				fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
			}
		}
		return fmt;
	}
};

/**
 * 生成随机字符串
 */
export const toAnyString = () => {
	const str: string = "xxxxx-xxxxx-4xxxx-yxxxx-xxxxx".replace(/[xy]/g, (c: string) => {
		const r: number = (Math.random() * 16) | 0;
		const v: number = c === "x" ? r : (r & 0x3) | 0x8;
		return v.toString();
	});
	return str;
};

export const generateUUID = () => {
	if (typeof crypto === "object") {
		if (typeof crypto.randomUUID === "function") {
			return crypto.randomUUID();
		}
		if (typeof crypto.getRandomValues === "function" && typeof Uint8Array === "function") {
			const callback = (c: any) => {
				const num = Number(c);
				return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(16);
			};
			return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, callback);
		}
	}
	let timestamp = new Date().getTime();
	let performanceNow = (typeof performance !== "undefined" && performance.now && performance.now() * 1000) || 0;
	return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
		let random = Math.random() * 16;
		if (timestamp > 0) {
			random = (timestamp + random) % 16 | 0;
			timestamp = Math.floor(timestamp / 16);
		} else {
			random = (performanceNow + random) % 16 | 0;
			performanceNow = Math.floor(performanceNow / 16);
		}
		return (c === "x" ? random : (random & 0x3) | 0x8).toString(16);
	});
};

/**
 * element plus 的文件大小 Formatter 实现
 *
 * @param row 行数据
 * @param column 字段
 * @param cellValue 字段值
 */
// @ts-ignore
export const fileSizeFormatter = (row, column, cellValue) => {
	const fileSize = cellValue;
	const unitArr = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
	const srcSize = parseFloat(fileSize);
	const index = Math.floor(Math.log(srcSize) / Math.log(1024));
	const size = srcSize / Math.pow(1024, index);
	const sizeStr = size.toFixed(2); //保留的小数位数
	return sizeStr + " " + unitArr[index];
};

/**
 * 将值复制到目标对象，且以目标对象属性为准，例：target: {a:1} source:{a:2,b:3} 结果为：{a:2}
 * @param target 目标对象
 * @param source 源对象
 */
export const copyValueToTarget = (target, source) => {
	const newObj = Object.assign({}, target, source);
	// 删除多余属性
	Object.keys(newObj).forEach((key) => {
		// 如果不是target中的属性则删除
		if (Object.keys(target).indexOf(key) === -1) {
			delete newObj[key];
		}
	});
	// 更新目标对象值
	Object.assign(target, newObj);
};

// TODO @puhui999：返回要带上 .00 哈.例如说 1.00
/**
 * 将一个整数转换为分数保留两位小数
 * @param num
 */
export const formatToFraction = (num: number | string | undefined): number => {
	if (typeof num === "undefined") return 0;
	const parsedNumber = typeof num === "string" ? parseFloat(num) : num;
	return parseFloat((parsedNumber / 100).toFixed(2));
};

/**
 * 将一个分数转换为整数
 * @param num
 */
export const convertToInteger = (num: number | string | undefined): number => {
	if (typeof num === "undefined") return 0;
	const parsedNumber = typeof num === "string" ? parseFloat(num) : num;
	// TODO 分转元后还有小数则四舍五入
	return Math.round(parsedNumber * 100);
};

/**
 * 将一个数转换为 1.00 这样
 * 数据呈现的时候使用
 *
 * @param num 整数
 */
export const floatToFixed2 = (num: number | string | undefined): string => {
	let str = "0.00";
	if (typeof num === "undefined") {
		return str;
	}
	const f = formatToFraction(num);
	const decimalPart = f.toString().split(".")[1];
	const len = decimalPart ? decimalPart.length : 0;
	switch (len) {
		case 0:
			str = f.toString() + ".00";
			break;
		case 1:
			str = f.toString() + "0";
			break;
		case 2:
			str = f.toString();
			break;
	}
	return str;
};

/**
 * 元转分
 */
export const yuanToFen = (amount: string | number): number => {
	return Math.round(Number(amount) * 100);
};

/**
 * 分转元
 */
export const fenToYuan = (amount: string | number): number => {
	return Number((Number(amount) / 100).toFixed(2));
};

// 防抖: 只执行最后一次, 定时器内触发则重新计时
export const debounceDirective = {
	beforeMount(el, binding) {
		let timer;
		const {
			arg,
			value: { fn, time, keys, params }
		} = binding;
		el.addEventListener(arg || "input", () => {
			clearTimeout(timer);
			timer = setTimeout(() => {
				fn(keys, params);
			}, time || 600); // 600毫秒防抖延迟，可以根据需求调整
		});
	}
};

// 节流: 控制执行次数, 定时器结束才会再次触发
export const throttleDirective: Directive<HTMLElement, (...args: any[]) => void> = {
	mounted(el, binding) {
		let timeout: any = null;
		const handler = () => {
			if (timeout) return;
			binding.value();
			timeout = setTimeout(() => {
				timeout = null;
			}, 500); // 节流时间，可以作为参数传递
		};

		el.addEventListener("click", handler);
	},
	beforeUnmount(el) {
		el.removeEventListener("click", el._v_throttleHandler);
	}
};

// 日期转时间戳
export const getTimestamp = (value) => {
	return new Date(value).getTime() / 1000;
};

// 获取当前时间
export const getCurrentDate = () => {
	const date = new Date();
	const year = date.getFullYear() + "";
	const month = date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1;
	const day = date.getDate() < 10 ? `0${date.getDate()}` : date.getDate();
	const h = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours();
	const m = date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes();
	const s = date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds();
	return `${year}-${month}-${day} ${h}:${m}:${s}`;
};

// 判断某个字符出现过几次
export const getCountSymbol = (symbol, str) => {
	// 使用正则表达式，'g'标志表示全局匹配
	const regex = new RegExp(symbol, "g");
	// match()方法返回所有匹配的数组，数组长度即为出现次数
	return (str.match(regex) || []).length;
};

// a标签下载文件
export const downFile = async (fileUrl: string, fileName: string) => {
	try {
		// 使用 fetch API 下载文件
		const response = await fetch(fileUrl);
		const blob = await response.blob();
		const url = URL.createObjectURL(blob);
		const link = document.createElement("a");
		link.href = url;
		// 文件名和后缀
		link.download = `${fileName}`;
		// 将 <a> 标签添加到页面中并模拟点击下载
		document.body.appendChild(link);
		link.click();
		// 下载完成后移除 <a> 标签和 URL 对象
		document.body.removeChild(link);
		URL.revokeObjectURL(url);
	} catch (error) {
		console.error("Error downloading the file:", error);
	}
};

// 千分位
export const formatNumber = (value, idx = 2) => {
	if (value === '') return '--';
	// 将数字转换为带有两位小数的格式
	const formattedValue = Number(value).toFixed(idx);
	// 使用正则表达式添加千分位分隔符
	return formattedValue.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};

// 判断两个对象除了特定值以外，是否都一样
export const isSame = (obj1, obj2, field) => {
	// 获取两个对象的键
	const keys1 = obj1 && Object.keys(obj1)?.filter((key) => key !== field);
	const keys2 = obj2 && Object.keys(obj2)?.filter((key) => key !== field);

	// 比较键的数量
	if (keys1.length !== keys2.length) {
		return false;
	}

	// 比较键的值
	for (const key of keys1) {
		if (obj1[key] !== obj2[key]) {
			return false;
		}
	}

	return true;
};

export const getDateDiff = (targetDate) => {
	const now = Date.now(); // 当前时间的时间戳（毫秒）
	const diff = now - new Date(targetDate).getTime(); // 时间差（毫秒）

	// 转换为秒、分钟、小时、天数
	const seconds = Math.floor(diff / 1000);
	const minutes = Math.floor(diff / (1000 * 60));
	const hours = Math.floor(diff / (1000 * 60 * 60));
	const days = Math.floor(diff / (1000 * 60 * 60 * 24));
	const month = Math.floor(diff / (1000 * 60 * 60 * 24 * 30));
	const years = Math.floor(diff / (1000 * 60 * 60 * 24 * 30 * 12));

	if (seconds < 60) return `刚刚`;
	if (minutes < 60) return `${minutes}分钟前`;
	if (hours < 24) return `${hours}小时前`;
	if (month>=1 && month < 12) return `${month}个月前`;
	if (years >= 1 && years < 12) return `${years}年前`;
	return `${days}天前`;
};

export function SelectInfo(list, value, labelKey = "label", valueKey = "value") {
	if (!Array.isArray(list)) return "";
	if (value === "") return "";
	const door = list.find((i) => i[valueKey] == value);
	return door ? door[labelKey] : "";
}

// 传递对象和key，返回值
export function getValue(obj, key) {
	try {
		const keys = key.split(".");
		let value = obj;
		for (let k of keys) {
			value = value[k];
		}
		return value;
	} catch (error) {
		return "";
	}
}

/**
 * 格式化金额
 * @param amount 金额数字
 * @param currencySymbol 金额单位，默认为 '￥'
 * @param unitType 是否转换单位，默认为 true
 * @returns 格式化后的金额字符串
 */
export function formatAmount(amount, currencySymbol = "¥", unitType = "") {
	let formattedAmount;
	let unitSuffix = "";

	switch (unitType) {
		case "K":
			formattedAmount = amount / 1000;
			unitSuffix = "K";
			break;
		case "W":
			formattedAmount = amount / 10000;
			unitSuffix = "W";
			break;
		case "SW":
			formattedAmount = amount / 100000;
			unitSuffix = "SW";
			break;
		case "M":
			formattedAmount = amount / 1000000;
			unitSuffix = "M";
			break;
		case "E":
			formattedAmount = amount / 100000000;
			unitSuffix = "E";
			break;
		default:
			formattedAmount = amount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
			break;
	}

	return `${currencySymbol}${formattedAmount}${unitSuffix}`;
}

export function formatPhone(phone: string, separator = "-") {
	if (!phone) return "";
	const formatted = phone.replace(/(\d{3})(\d{4})(\d{4})/, `$1${separator}$2${separator}$3`);
	return formatted;
}

export const formatMoney = (num, decimal = 2, split = ",", pre = "¥", next = "") => {
	/*
		parameter：
		num：格式化目标数字
		decimal：保留几位小数，默认2位
		split：千分位分隔符，默认为,
		moneyFormat(123456789.87654321, 2, ',') // 123,456,789.88
	*/
	if (isFinite(num) && num != null) {
		// num是数字
		if (num === 0) {
			// 为0
			return pre + num.toFixed(decimal) + next;
		} else {
			// 非0
			let res = "";
			const dotIndex = String(num).indexOf(".");
			if (dotIndex === -1) {
				// 整数
				if (decimal === 0) {
					res = String(num).replace(/(\d)(?=(?:\d{3})+$)/g, `$1${split}`);
				} else {
					res = String(num).replace(/(\d)(?=(?:\d{3})+$)/g, `$1${split}`) + "." + "0".repeat(decimal);
				}
			} else {
				// 非整数
				// js四舍五入 Math.round()：正数时4舍5入，负数时5舍6入
				// Math.round(1.5) = 2
				// Math.round(-1.5) = -1
				// Math.round(-1.6) = -2
				// 保留decimals位小数
				const numStr = String((Math.round(num * Math.pow(10, decimal)) / Math.pow(10, decimal)).toFixed(decimal)); // 四舍五入，然后固定保留2位小数
				const decimals = numStr.slice(dotIndex, dotIndex + decimal + 1); // 截取小数位
				res = String(numStr.slice(0, dotIndex)).replace(/(\d)(?=(?:\d{3})+$)/g, `$1${split}`) + decimals;
			}
			return pre + res + next;
		}
	} else {
		return "--";
	}
};

// 日期，是否显示时分秒，切换显示年月日
export function formatDate(date: Date | string, showTime: boolean = false, formatType: string = "yearMonthDay"): string {
    if (!date) return '--';

    // 处理字符串日期
    if (typeof date === 'string') {
        if (/^\d{4}$/.test(date)) { // 匹配年份格式如 "2024"
            date = new Date(parseInt(date), 0, 1); // 设置为该年的1月1日
        } else if (/^\d{4}-\d{2}$/.test(date)) { // 匹配年月格式如 "2024-10"
            const [year, month] = date.split('-').map(Number);
            date = new Date(year, month - 1, 1); // 设置为该年的指定月的1日
        } else {
            date = new Date(date); // 尝试直接转换为Date对象
        }
    }

    if (!(date instanceof Date) || isNaN(date.getTime())) return '--'; // 验证日期对象是否有效

    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");
    const seconds = String(date.getSeconds()).padStart(2, "0");

    let formattedDate = "";

    switch (formatType) {
        case "year":
            formattedDate = `${year}`;
            break;
        case "month":
            formattedDate = `${year}/${month}`;
            break;
        default:
            formattedDate = `${year}/${month}/${day}`;
            break;
    }

    if (showTime) {
        formattedDate += ` ${hours}:${minutes}:${seconds}`;
    }

    return formattedDate;
}



export const isValid = (value) => {
    return value !== null && value !== '' && value !== undefined
}

// 创建并触发自定义事件
export const sendMessage = (data) => {
    var event = new CustomEvent('receiveMessage', { detail: data });
    window.dispatchEvent(event);
}